package com.zy.gmall0401.manage.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.zy.gmall0401.bean.*;
import com.zy.gmall0401.manage.mapper.*;
import com.zy.gmall0401.service.ManageService;
import com.zy.gmall0401.util.RedisUtil;
import org.apache.commons.lang3.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import redis.clients.jedis.Jedis;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.concurrent.TimeUnit;


@Service
public class ManageServiceImpl implements ManageService {


    @Autowired
    RedisUtil redisUtil;

    @Autowired
    SkuAttrValueMapper skuAttrValueMapper;
    @Autowired
    SkuImageMapper skuImageMapper;
    @Autowired
    SkuInfoMapper skuInfoMapper;
    @Autowired
    SkuSaleAttrValueMapper skuSaleAttrValueMapper;
    @Autowired
    SpuImageMapper spuImageMapper;
    @Autowired
    SpuInfoMapper spuInfoMapper;
    @Autowired
    SpuSaleAttrMapper spuSaleAttrMapper;
    @Autowired
    SpuSaleAttrValueMapper spuSaleAttrValueMapper;

    @Autowired
    BaseSaleAttrMapper baseSaleAttrMapper;

    @Autowired
    BaseAttrValueMapper baseAttrValueMapper;

    @Autowired
    BaseAttrInfoMapper baseAttrInfoMapper;

    @Autowired
    BaseCatalog1Mapper baseCatalog1Mapper;

    @Autowired
    BaseCatalog2Mapper baseCatalog2Mapper;

    @Autowired
    BaseCatalog3Mapper baseCatalog3Mapper;
    //设置key的前缀
    public static final String SKUKEY_PREFIX = "sku";
    //设置key的后缀
    public static final String SKUKEY_INFO_SUFFIX = ":info";
    //设置锁的后缀
    public static final String SKUKEY_LOCK_SUFFIX = ":lock";

    @Override
    public List<BaseCatalog1> getCatalog1() {
        return baseCatalog1Mapper.selectAll();
    }

    @Override
    public List<BaseCatalog2> getCatalog2(String catalog1Id) {
        BaseCatalog2 baseCatalog2 = new BaseCatalog2();
        baseCatalog2.setCatalog1Id(catalog1Id);
        List<BaseCatalog2> baseCatalog2List = baseCatalog2Mapper.select(baseCatalog2);
        return baseCatalog2List;
    }

    @Override
    public List<BaseCatalog3> getCatalog3(String catalog2Id) {
        BaseCatalog3 baseCatalog3 = new BaseCatalog3();
        baseCatalog3.setCatalog2Id(catalog2Id);
        List<BaseCatalog3> baseCatalog3List = baseCatalog3Mapper.select(baseCatalog3);
        return baseCatalog3List;
    }

    @Override
    public List<BaseAttrInfo> getAttrList(String catalog3Id) {

//        Example example = new Example(BaseAttrInfo.class);
//        example.createCriteria().andEqualTo("catalog3Id",catalog3Id);
//        List<BaseAttrInfo> baseAttrInfoList = baseAttrInfoMapper.selectByExample(example);
//        //查询平台属性值
//        for (BaseAttrInfo baseAttrInfo : baseAttrInfoList) {
//            BaseAttrValue baseAttrValue = new BaseAttrValue();
//            baseAttrValue.setAttrId(baseAttrInfo.getId());
//            List<BaseAttrValue> baseAttrValueList = baseAttrValueMapper.select(baseAttrValue);
//            baseAttrInfo.setAttrValueList(baseAttrValueList);
//        }

        List<BaseAttrInfo> baseAttrList = baseAttrInfoMapper.getBaseAttrInfoListByCatalog3Id(catalog3Id);


        return baseAttrList;
    }

    @Override
    public BaseAttrInfo getBaseAttrInfo(String attrId) {
        BaseAttrInfo baseAttrInfo = baseAttrInfoMapper.selectByPrimaryKey(attrId);

        BaseAttrValue baseAttrValueQuery = new BaseAttrValue();
        baseAttrValueQuery.setAttrId(attrId);
        List<BaseAttrValue> baseAttrValueList = baseAttrValueMapper.select(baseAttrValueQuery);

        baseAttrInfo.setAttrValueList(baseAttrValueList);

        return baseAttrInfo;
    }

    @Override
    @Transactional
    public void saveAttrInfo(BaseAttrInfo baseAttrInfo) {
        if (baseAttrInfo.getId() != null && baseAttrInfo.getId().length() > 0) {
            baseAttrInfoMapper.updateByPrimaryKeySelective(baseAttrInfo);
        } else {
            baseAttrInfo.setId(null);
            baseAttrInfoMapper.insertSelective(baseAttrInfo);
        }
        Example example = new Example(BaseAttrValue.class);
        example.createCriteria().andEqualTo("attrId", baseAttrInfo.getId());
        //根据attrid先全部删除，再统一保存
        baseAttrValueMapper.deleteByExample(example);

        List<BaseAttrValue> attrValueList = baseAttrInfo.getAttrValueList();
        for (BaseAttrValue baseAttrValue : attrValueList) {
            String id = baseAttrInfo.getId();
            baseAttrValue.setAttrId(id);
            baseAttrValueMapper.insertSelective(baseAttrValue);
        }


    }

    @Override
    public List<BaseSaleAttr> getBaseSaleAttrList() {
        return baseSaleAttrMapper.selectAll();
    }

    @Override
    public void saveSpuInfo(SpuInfo spuInfo) {
        //spu基本信息
        spuInfoMapper.insertSelective(spuInfo);
        // 图片信息
        List<SpuImage> spuImageList = spuInfo.getSpuImageList();
        for (SpuImage spuImage : spuImageList) {
            spuImage.setSpuId(spuInfo.getId());
            spuImageMapper.insertSelective(spuImage);
        }

        // 销售属性
        List<SpuSaleAttr> spuSaleAttrList = spuInfo.getSpuSaleAttrList();
        for (SpuSaleAttr spuSaleAttr : spuSaleAttrList) {
            spuSaleAttr.setSpuId(spuInfo.getId());
            spuSaleAttrMapper.insertSelective(spuSaleAttr);

            // 销售属性值
            List<SpuSaleAttrValue> spuSaleAttrValueList = spuSaleAttr.getSpuSaleAttrValueList();
            for (SpuSaleAttrValue spuSaleAttrValue : spuSaleAttrValueList) {
                spuSaleAttrValue.setSpuId(spuInfo.getId());
                spuSaleAttrValueMapper.insertSelective(spuSaleAttrValue);
            }

        }

    }

    @Override
    public List<SpuInfo> getSpuList(String catalog3Id) {
        SpuInfo spuInfo = new SpuInfo();
        spuInfo.setCatalog3Id(catalog3Id);
        return spuInfoMapper.select(spuInfo);
    }

    @Override
    public List<SpuImage> getSpuImageList(String spuId) {
        SpuImage spuImage = new SpuImage();
        spuImage.setSpuId(spuId);
        return spuImageMapper.select(spuImage);
    }

    @Override
    public List<SpuSaleAttr> getSpuSaleAttrList(String spuId) {
        return spuSaleAttrMapper.getSpuSaleAttrListBySpuId(spuId);
    }

    @Override
    @Transactional
    public String saveSkuInfo(SkuInfo skuInfo) {
        //保存 1 基本信息
        if (skuInfo.getId() == null || skuInfo.getId().length() == 0) {
            skuInfoMapper.insertSelective(skuInfo);
        } else {
            skuInfoMapper.updateByPrimaryKeySelective(skuInfo);
        }
        //2 平台属性
        SkuAttrValue skuAttrValue = new SkuAttrValue();
        skuAttrValue.setSkuId(skuInfo.getId());
        skuAttrValueMapper.delete(skuAttrValue);

        List<SkuAttrValue> skuAttrValueList = skuInfo.getSkuAttrValueList();
        for (SkuAttrValue attrValue : skuAttrValueList) {
            attrValue.setSkuId(skuInfo.getId());
            skuAttrValueMapper.insertSelective(attrValue);
        }


        //3 销售属性
        SkuSaleAttrValue skuSaleAttrValue = new SkuSaleAttrValue();
        skuSaleAttrValue.setSkuId(skuInfo.getId());
        skuSaleAttrValueMapper.delete(skuSaleAttrValue);
        List<SkuSaleAttrValue> skuSaleAttrValueList = skuInfo.getSkuSaleAttrValueList();
        for (SkuSaleAttrValue saleAttrValue : skuSaleAttrValueList) {
            saleAttrValue.setSkuId(skuInfo.getId());
            skuSaleAttrValueMapper.insertSelective(saleAttrValue);

        }

        //4 图片
        SkuImage skuImage4Del = new SkuImage();
        skuImage4Del.setId(skuInfo.getId());
        skuImageMapper.delete(skuImage4Del);
        List<SkuImage> skuImageList = skuInfo.getSkuImageList();
        for (SkuImage skuImage : skuImageList) {
            skuImage.setSkuId(skuInfo.getId());
            skuImageMapper.insertSelective(skuImage);
        }

        return "success";


    }

    //查询数据库的数据
    public SkuInfo getSkuInfoDB(String skuId) {
        System.err.println(Thread.currentThread() + "读取数据库！！");
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        SkuInfo skuInfo = skuInfoMapper.selectByPrimaryKey(skuId);
        if (skuInfo == null) {
            return null;
        }
        //图片
        SkuImage skuImage = new SkuImage();
        skuImage.setSkuId(skuId);
        List<SkuImage> skuImageList = skuImageMapper.select(skuImage);
        skuInfo.setSkuImageList(skuImageList);

        //销售属性
        SkuSaleAttrValue skuSaleAttrValue = new SkuSaleAttrValue();
        skuSaleAttrValue.setSkuId(skuId);
        List<SkuSaleAttrValue> skuSaleAttrValueList = skuSaleAttrValueMapper.select(skuSaleAttrValue);
        skuInfo.setSkuSaleAttrValueList(skuSaleAttrValueList);

        //平台属性
        SkuAttrValue skuAttrValue = new SkuAttrValue();
        skuAttrValue.setSkuId(skuId);
        List<SkuAttrValue> skuAttrValueList = skuAttrValueMapper.select(skuAttrValue);
        skuInfo.setSkuAttrValueList(skuAttrValueList);


        return skuInfo;
    }


    //基于redisson ，引入的第三方包来实现的
    public SkuInfo getSkuInfo(String skuId) {
//先查询redis 若是没有在去查询数据库的数据
        //先查询redis 若是没有在去查询数据库的数据
        SkuInfo skuInfo = null;
        Jedis jedis = redisUtil.getJedis();

        int SKU_EXPIRE_SEC = 1000; //定义key的过期时间
        String key = SKUKEY_PREFIX + skuId + SKUKEY_INFO_SUFFIX;
        String s = jedis.get(key);
        if (s != null) {
//            查询的是缓存中的数据
            System.out.println(Thread.currentThread() + "这个线程------命中缓存");
//            把字符串转换成json数据
            if (!"EMPTY".equals(s)) {
                skuInfo = JSON.parseObject(s, SkuInfo.class);
            }

        } else {
            Config config = new Config();  //注意不要导错包  使用redisson的包
            //初始化单个服务器的配置
            config.useSingleServer().setAddress("redis://192.168.152.137:6379").setPassword("123456"); //redis的服务器地址redis设置 密码了
            //config.useSingleServer().setAddress("redis://81.70.20.241:6379"); //redis的服务器地址不需要redis密码的
            RedissonClient redissonClient = Redisson.create(config);
            String keylock = SKUKEY_PREFIX + skuId + SKUKEY_LOCK_SUFFIX;
            RLock rLock = redissonClient.getLock(keylock);
//            rLock.lock(10, TimeUnit.SECONDS);//给锁加一个时间
            boolean b = false;
            try {
                b = rLock.tryLock(100, 50, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (b) {
//            得到锁后直接查询缓存 ，不用查询数据库了
                String skuInfoJson = jedis.get(skuId);
                if (skuInfoJson != null) {
//                查询的是缓存中的数据
                    System.out.println(Thread.currentThread() + "这个线程------命中缓存");
//            把字符串转换成json数据
                    if (!"EMPTY".equals(s)) {
                        skuInfo = JSON.parseObject(s, SkuInfo.class);
                    }
                } else {
                    System.out.println(Thread.currentThread() + "这个线程====未命中缓存");
                    skuInfo = getSkuInfoDB(skuId);
//            把查到的数据放到 缓存中去
                    System.out.println(Thread.currentThread() + "把数据写入到 缓存中去");
                    //=====--查询数据库 和缓存中不存在的数据，会绕过缓存，和数据库，造成io过大（又是一种穿透）
                    String jsonResult = null;
                    if (skuInfo != null) {
                        jsonResult = JSON.toJSONString(skuInfo);
                    } else {
//                    查询对象为空，返回EMPTY
                        jsonResult = "EMPTY";
                    }
                    String setex = jedis.setex(key, SKU_EXPIRE_SEC, jsonResult);
                }
                rLock.unlock();

            }
        }

        return skuInfo;

    }

    // 查询缓存中的数据，若缓存中没有，就再去查询数据库 ，然后保存一份到 Redids中去
    public SkuInfo getSkuInfo_redis(String skuId) {
        //先查询redis 若是没有在去查询数据库的数据
        Jedis jedis = redisUtil.getJedis();
        SkuInfo skuInfo = null;
        int SKU_EXPIRE_SEC = 1000; //定义key的过期时间
        String key = SKUKEY_PREFIX + skuId + SKUKEY_INFO_SUFFIX;
        String s = jedis.get(key);
        if (s != null) {
//            查询的是缓存中的数据
            System.out.println(Thread.currentThread() + "这个线程------命中缓存");
//            把字符串转换成json数据
            if (!"EMPTY".equals(s)) {
                skuInfo = JSON.parseObject(s, SkuInfo.class);
            }

        } else {
            //redis的数据击穿如何解决    可以利用锁来解决这个 问题   setnx ---->  查锁和抢锁
//定义锁的结构    type string   key  sku:001:lock   value ...
            String keylock = SKUKEY_PREFIX + skuId + SKUKEY_LOCK_SUFFIX;
//            Long aLong = jedis.setnx(keylock, "lock");
//            jedis.expire(keylock, 10);
            // 设置redis的时间并判断(1.线程占用锁的时间过长)（2.TODO）
            String token = UUID.randomUUID().toString();
            String aLong = jedis.set(keylock, token, "NX", "EX", 10);
//            if (aLong == 1) {
            if ("OK".equals(aLong)) {
                //查询是数据库的数据
                System.out.println(Thread.currentThread() + "得到锁");
                System.out.println(Thread.currentThread() + "这个线程====未命中缓存");
                skuInfo = getSkuInfoDB(skuId);
//            把查到的数据放到 缓存中去
                System.out.println(Thread.currentThread() + "把数据写入到 缓存中去");
                //=====--查询数据库 和缓存中不存在的数据，会绕过缓存，和数据库，造成io过大（又是一种穿透）
                String jsonResult = null;
                if (skuInfo != null) {
                    jsonResult = JSON.toJSONString(skuInfo);
                } else {
//                    查询对象为空，返回EMPTY
                    jsonResult = "EMPTY";
                }


                String setex = jedis.setex(key, SKU_EXPIRE_SEC, jsonResult);
//                锁需要释放
                System.out.println(Thread.currentThread() + "关闭锁======");
//                判断锁是否存在且token值是否相等（同时满足）
                if (jedis.exists(keylock) && token.equals(jedis.get(keylock))) {
                    jedis.del(keylock);//但是这个不知道释放谁的锁对应的key
                }

            } else {

                try {
                    // 没有获取到锁，继续等待，然后在重新调用
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //然后在自旋
                getSkuInfo(skuId);
            }

        }


        jedis.close();
        return skuInfo;
    }


    @Override
    public List<SpuSaleAttr> getSpuSaleAttrListCheckSku(String skuId, String spuId) {
        List<SpuSaleAttr> spuSaleAttrList = spuSaleAttrMapper.getSpuSaleAttrListBySpuIdCheckSku(skuId, spuId);
        return spuSaleAttrList;
    }

    @Override
    public Map getSkuValueIdsMap(String spuId) {
        List<Map> mapList = skuSaleAttrValueMapper.getSaleAttrValuesBySpu(spuId);
        Map skuValueIdsMap = new HashMap();

        for (Map map : mapList) {
            String skuId = (Long) map.get("sku_id") + "";
            String valueIds = (String) map.get("value_ids");
            skuValueIdsMap.put(valueIds, skuId);


        }
        return skuValueIdsMap;
    }

    /**
     * @return 通过 多个平台属性值查询平台列表集合
     * @Description: java类作用描述
     * @Author: == zy
     * @Version: 1.0
     */

    @Override
    public List<BaseAttrInfo> getAttrList(List attrValueIdList) {
        //attrValueIdList -->  13,15, 54   把集合转换成字符串
        String valueIds = StringUtils.join(attrValueIdList.toArray(), ",");

        List<BaseAttrInfo> baseAttrInfoListByValueIds = baseAttrInfoMapper.getBaseAttrInfoListByValueIds(valueIds);
        return baseAttrInfoListByValueIds;


    }

    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add("aaa");
        arrayList.add("bbb");
        arrayList.add("ccc");
        arrayList.add("ddd");
        Object[] objects = arrayList.toArray();
        String value = StringUtils.join(objects, ",");
        System.out.println(value);
    }


}
